// Copyright © 2022 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package clam

import (
	"reflect"
	"testing"

	"github.com/openclarity/openclarity/scanner/families/malware/types"
)

func Test_ParseMalwareScanOutput(t *testing.T) {
	testCases := []struct {
		name            string
		clamOutput      string
		expectedMalware []types.Malware
		expectedScanned int
	}{
		{
			name: "Malware found",
			clamOutput: `
				/path/to/file.txt: OK
				/path/to/malware.exe: Win.Trojan.Generic-1 TROJAN FOUND
				/path/to/another/file.pdf: OK
				
				----------- SCAN SUMMARY -----------
				Known viruses: 123456
				Engine version: 0.103.4
				Scanned directories: 3
				Scanned files: 10
				Infected files: 1
				Data scanned: 1.00 MB
				Data read: 0.50 MB (ratio 2.00:1)
				Time: 0.020 sec (0 m 0 s)
			`,
			expectedMalware: []types.Malware{
				{
					MalwareName: "Generic-1",
					MalwareType: "TROJAN",
					Path:        "/path/to/malware.exe",
				},
			},
			expectedScanned: 10,
		},
		{
			name: "No malware found",
			clamOutput: `
				/path/to/file.txt: OK
				/path/to/another/file.pdf: OK
				
				----------- SCAN SUMMARY -----------
				Known viruses: 123456
				Engine version: 0.103.4
				Scanned directories: 3
				Scanned files: 2
				Infected files: 0
				Data scanned: 1.00 MB
				Data read: 0.50 MB (ratio 2.00:1)
				Time: 0.020 sec (0 m 0 s)
			`,
			expectedMalware: []types.Malware{},
			expectedScanned: 2,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			malwareList, summary := parseMalwareScanOutput(tc.clamOutput)

			if len(malwareList) != len(tc.expectedMalware) {
				t.Fatalf("Expected %d malwares, but got %d", len(tc.expectedMalware), len(malwareList))
			}

			for i, expectedMalware := range tc.expectedMalware {
				malware := (malwareList)[i]
				if !reflect.DeepEqual(malware, expectedMalware) {
					t.Errorf("Malware %d: expected %v, but got %v", i, expectedMalware, malware)
				}
			}

			if summary.ScannedFiles != tc.expectedScanned {
				t.Fatalf("Expected %v scanned files, but got %v", tc.expectedScanned, summary.ScannedFiles)
			}
		})
	}
}

func Test_ExtractMalwareInfo(t *testing.T) {
	tests := []struct {
		name     string
		words    []string
		expected *types.Malware
	}{
		{
			name:  "Malware found",
			words: []string{"/path/to/malware.exe:", "Win.Trojan.Generic-123", "FOUND"},
			expected: &types.Malware{
				MalwareName: "Generic-123",
				MalwareType: "TROJAN",
				Path:        "/path/to/malware.exe",
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := extractDetectedMalware(tt.words); !reflect.DeepEqual(got, tt.expected) {
				t.Errorf("extractDetectedMalware() = %v, want %v", got, tt.expected)
			}
		})
	}
}

func Test_parseScanSummary(t *testing.T) {
	testCases := []struct {
		name     string
		input    string
		expected *types.ScanSummary
	}{
		{
			name: "Summary with all fields",
			input: `
				/path/to/file.txt: OK
				/path/to/malware.exe: Win.Trojan.Generic-1 TROJAN FOUND
				/path/to/another/file.pdf: OK

				----------- SCAN SUMMARY -----------
				Known viruses: 123456
				Engine version: 0.103.4
				Scanned directories: 3
				Scanned files: 10
				Infected files: 1
				Data scanned: 1.00 MB
				Data read: 0.50 MB (ratio 2.00:1)
				Time: 0.020 sec (0 m 0 s)
			`,
			expected: &types.ScanSummary{
				KnownViruses:       123456,
				EngineVersion:      "0.103.4",
				ScannedDirectories: 3,
				ScannedFiles:       10,
				InfectedFiles:      1,
				DataScanned:        "1.00 MB",
				DataRead:           "0.50 MB (ratio 2.00:1)",
				TimeTaken:          "0.020 sec (0 m 0 s)",
			},
		},
		{
			name: "Empty summary",
			input: `
				/path/to/file.txt: OK
				/path/to/another/file.pdf: OK

				----------- SCAN SUMMARY -----------
				Known viruses: 0
				Engine version: 0.103.4
				Scanned directories: 0
				Scanned files: 0
				Infected files: 0
				Data scanned: 0.00 MB
				Data read: 0.00 MB (ratio 0.00:1)
				Time: 0.000 sec (0 m 0 s)
			`,
			expected: &types.ScanSummary{
				KnownViruses:       0,
				EngineVersion:      "0.103.4",
				ScannedDirectories: 0,
				ScannedFiles:       0,
				InfectedFiles:      0,
				DataScanned:        "0.00 MB",
				DataRead:           "0.00 MB (ratio 0.00:1)",
				TimeTaken:          "0.000 sec (0 m 0 s)",
			},
		},
		{
			name:     "Empty input",
			input:    "",
			expected: &types.ScanSummary{},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			summary := parseScanSummary(tc.input)

			if !reflect.DeepEqual(summary, tc.expected) {
				t.Errorf("Expected %v, but got %v", tc.expected, summary)
			}
		})
	}
}
